using System.Collections.Generic;
using BitTorrent.Bencode;
using BitTorrent.Bencode.Collections;
using BitTorrent.File.Exceptions;

namespace BitTorrent.File {
    internal class MultiFile : Info {
        public MultiFile() {
        }

        public MultiFile(Dictionary info) : base(info) {
            DirectoryName = GetDirectoryName(info);
            Files = GetTorrentFiles(info);
        }

        /// <summary>
        /// If in single file mode (Files is empty) Name represents the filename of the file.
        /// If in multiple file mode (Files is not empty) Name represents the directory to store all the files.
        /// </summary>
        public string DirectoryName { get; set; }

        /// <summary>
        /// Determines whether [is multi file info] [the specified info].
        /// </summary>
        /// <param name="info">The info.</param>
        /// <returns>
        /// 	<c>true</c> if [is multi file info] [the specified info]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsMultiFileInfo(Dictionary info) {
            return info.ContainsKey("files");
        }

        public IEnumerable<File> Files { get; set; }

        internal override Dictionary GetDictionary() {
            var dictionary = base.GetDictionary();

            dictionary.Add((ByteString)"name", new ByteString { String = DirectoryName });
            var metaFiles = new List();
            foreach (var item in Files) {
                metaFiles.Add(item.GetDictionary());
            }
            dictionary.Add((ByteString)"files", metaFiles);

            return dictionary;
        }

        private static string GetDirectoryName(Dictionary info) {
            // In multi file mode name is the directory name.
            if (!info.ContainsKey("name")) {
                throw new TorrentFileException("No info name field found");
            }

            var name = info["name"] as ByteString;
            if (name == null) {
                throw new TorrentFileException("name is not represented by a Bencode.ByteString");
            }

            return name.String;
        }

        private static IEnumerable<File> GetTorrentFiles(Dictionary info) {
            if (!info.ContainsKey("files"))
                yield break;

            var files = info["files"] as List;
            if (files == null)
                yield break;

            foreach (var item in files) {
                if (!(item is Dictionary)) {
                    throw new TorrentFileException("files list can only contain Bencode.Dictonary's");
                }

                yield return new File((Dictionary)item);
            }
        }
    }
}